package stud.mpgame.network;

import stud.mpgame.network.Message;
import stud.mpgame.network.IMessageDispatcher;
import stud.mpgame.network.NetworkMonitor;
import flash.utils.TypedDictionary;
import stud.mpgame.network.util.ResponseMessageDescription;
import stud.mpgame.network.util.ResponseUserObject;

/**
 * ...
 * @author Timofeev
 */

class MessageDispatcher implements IMessageDispatcher {
    
    private var receivedListeners:List<Message-> Void>;
    private var descriptionReceivedListeners:TypedDictionary<MessageDescription, List<Message-> Void>>;
    private var responseReceivedListeners:List<Message-> Void>;
    private var descriptionResponseReceivedListeners:TypedDictionary<MessageDescription, List<Message-> Void>>;
    private var sentListeners:List<Message-> Void>;
    private var descriptionSentListeners:TypedDictionary<MessageDescription, List<Message-> Void>>;
    private var responseSentListeners:List<Message-> Void>;
    private var descriptionResponseSentListeners:TypedDictionary<MessageDescription, List<Message-> Void>>;
    
    private var networkMonitor:NetworkMonitor;
    
    public function new(networkMonitor:NetworkMonitor) {
        this.networkMonitor = networkMonitor;
        receivedListeners = new List<Message-> Void>();
        descriptionReceivedListeners = new TypedDictionary<MessageDescription, List<Message-> Void>>();
        responseReceivedListeners = new List<Message-> Void>();
        descriptionResponseReceivedListeners = new TypedDictionary<MessageDescription, List<Message-> Void>>();
        sentListeners = new List<Message-> Void>();
        descriptionSentListeners = new TypedDictionary<MessageDescription, List<Message-> Void>>();
        responseSentListeners = new List<Message-> Void>();
        descriptionResponseSentListeners = new TypedDictionary<MessageDescription, List<Message-> Void>>();
    }
    
    public function addMessageReceivedListener(listener:Message->Void):Void {
        receivedListeners.add(listener);
    }
    
    public function addMessageReceivedListenerByDescr(messageDescription:MessageDescription, listener:Message-> Void):Void {
        var currentListeners:List<Message-> Void> = descriptionReceivedListeners.get(messageDescription);
        if (currentListeners == null) {
            currentListeners = new List<Message-> Void>();           
        }
        currentListeners.add(listener);
        descriptionReceivedListeners.set(messageDescription, currentListeners);
    }
    
    public function addResponseMessageReceivedListener(listener:Message-> Void):Void {
        responseReceivedListeners.add(listener);
    }
    
    public function addResponseMessageReceivedListenerByDescr(messageDescription:MessageDescription, listener:Message-> Void):Void {
        var currentListeners:List<Message-> Void> = descriptionResponseReceivedListeners.get(messageDescription);
        if (currentListeners == null) {
            currentListeners = new List<Message-> Void>();            
        }
        currentListeners.add(listener);
        descriptionResponseReceivedListeners.set(messageDescription, currentListeners);
    }

    public function addMessageSentListener(listener:Message-> Void):Void {
        sentListeners.add(listener);
    }
    
    public function addMessageSentListenerByDescr(messageDescription:MessageDescription, listener:Message-> Void):Void {
        var currentListeners:List<Message-> Void> = descriptionSentListeners.get(messageDescription);
        if (currentListeners == null) {
            currentListeners = new List<Message->Void>();           
        }
        currentListeners.add(listener);
        descriptionSentListeners.set(messageDescription, currentListeners);
    }
    
    public function addResponseMessageSentListener(listener:Message-> Void):Void {        
        responseSentListeners.add(listener);
    }
    
    public function addResponseMessageSentListenerByDescr(messageDescription:MessageDescription, listener:Message-> Void):Void {
        var currentListeners:List<Message-> Void> = descriptionResponseSentListeners.get(messageDescription);
        if (currentListeners == null) {
            currentListeners = new List<Message-> Void>();            
        }
        currentListeners.add(listener);
        descriptionResponseSentListeners.set(messageDescription, currentListeners);
    }

    public function removeMessageReceivedListener(listener:Message-> Void):Void {
        receivedListeners.remove(listener);
    }
    
    public function removeMessageReceivedListenerByDescr(messageDescription:MessageDescription, listener:Message-> Void):Void {
        descriptionReceivedListeners.get(messageDescription).remove(listener);
    }
    
    public function removeResponseMessageReceivedListener(listener:Message-> Void):Void {
        responseReceivedListeners.remove(listener);
    }
    
    public function removeResponseMessageReceivedListenerByDescr(messageDescription:MessageDescription, listener:Message-> Void):Void {
        descriptionResponseReceivedListeners.get(messageDescription).remove(listener);
    }

    public function removeMessageSentListener(listener:Message-> Void):Void {
        sentListeners.remove(listener);
    }
    
    public function removeMessageSentListenerByDescr(messageDescription:MessageDescription, listener:Message-> Void):Void {
        descriptionSentListeners.get(messageDescription).remove(listener);
    }
    
    public function removeResponseMessageSentListener(listener:Message-> Void):Void {
        responseSentListeners.remove(listener);
    }
    
    public function removeResponseMessageSentListenerByDescr(messageDescription:MessageDescription, listener:Message-> Void):Void {
        descriptionResponseSentListeners.get(messageDescription).remove(listener);
    }
    
    public function messageReceived(message:Message):Void {
        for (currentListener in receivedListeners) {
            currentListener(message);
        }
        var messageDescription:MessageDescription = message.getMessageDescription();
        if (messageDescription.getAutoResponseFlag()) {
            var responseMessageDescription:MessageDescription = ResponseMessageDescription.getInstance();
            var responseMessage:Message = new Message(networkMonitor, responseMessageDescription);            
            var responseUserObject:UserObject = new ResponseUserObject(messageDescription, message.getSerialNumber(), message.getSentTime(), message.getReceivedTime());
            responseMessage.putUserObject(responseUserObject);            
            responseMessage.send();
        }
        var currentListeners:List<Message-> Void> = descriptionReceivedListeners.get(messageDescription);
        if (currentListeners != null) {
            for (currentListener in currentListeners) {
                currentListener(message);
            }
        }
		if(messageDescription.getID() == ResponseMessageDescription.getInstance().getID()) {
			var responseUserObject:ResponseUserObject = cast(message.getUserObject(ResponseUserObject), ResponseUserObject);
            var messageDescription:MessageDescription = responseUserObject.getMessageDescription();
            for (currentListener in responseReceivedListeners) {
                currentListener(message);
            }
            var currentListeners:List<Message -> Void> = descriptionResponseReceivedListeners.get(messageDescription);
            for (currentListener in currentListeners) {
                currentListener(message);
            }
		}
    }
    
    public function messageSent(message:Message):Void {        
        for (currentListener in sentListeners) {
            currentListener(message);
        }
        var messageDescription:MessageDescription = message.getMessageDescription();
        var currentListeners:List<Message -> Void> = descriptionSentListeners.get(messageDescription);
        if (currentListeners != null) {
            for (currentListener in currentListeners) {
                currentListener(message);
            }
        }
		if(messageDescription.getID() == ResponseMessageDescription.getInstance().getID()) {
			var responseUserObject:ResponseUserObject = cast(message.getUserObject(ResponseUserObject), ResponseUserObject);
            var messageDescription:MessageDescription = responseUserObject.getMessageDescription();
            for (currentListener in responseSentListeners) {
                currentListener(message);
            }
            var currentListeners:List<Message -> Void> = descriptionResponseSentListeners.get(messageDescription);
            for (currentListener in currentListeners) {
                currentListener(message);
            }
        }
    }
    
}